package l1j.opqlo.NewSystem.Attack;

import static l1j.server.server.model.skill.L1SkillId.BERSERKERS;
import static l1j.server.server.model.skill.L1SkillId.BURNING_SPIRIT;
import static l1j.server.server.model.skill.L1SkillId.BURNING_WEAPON;
import static l1j.server.server.model.skill.L1SkillId.ELEMENTAL_FIRE;
import static l1j.server.server.model.skill.L1SkillId.FIRE_BLESS;
import static l1j.server.server.model.skill.L1SkillId.FIRE_WEAPON;
import static l1j.server.server.model.skill.L1SkillId.FOE_SLAYER;
import static l1j.server.server.model.skill.L1SkillId.SPECIAL_EFFECT_WEAKNESS_LV1;
import static l1j.server.server.model.skill.L1SkillId.SPECIAL_EFFECT_WEAKNESS_LV2;
import static l1j.server.server.model.skill.L1SkillId.SPECIAL_EFFECT_WEAKNESS_LV3;

import java.util.ConcurrentModificationException;

import l1j.server.server.ActionCodes;
import l1j.server.server.model.L1Character;
import l1j.server.server.model.L1WeaponSkill;
import l1j.server.server.model.Instance.L1ItemInstance;
import l1j.server.server.model.Instance.L1NpcInstance;
import l1j.server.server.model.Instance.L1PcInstance;
import l1j.server.server.serverpackets.S_AttackMissPacket;
import l1j.server.server.serverpackets.S_DoActionGFX;
import l1j.server.server.serverpackets.S_SkillIconGFX;
import l1j.server.server.serverpackets.S_UseAttackSkill;
import l1j.server.server.templates.L1Item;
import l1j.server.server.utils.Random;

public abstract class L1AttackModel {

	/**
	 * 技能增加閃避
	 *
	 * @param character
	 * @return
	 */
	protected static int attackerDice(final L1Character character) {

		int attackerDice = 0;
		if (character.getDodge() > 0) {
			attackerDice -= character.getDodge();
		}
		if (character.getNdodge() > 0) {
			attackerDice += character.getNdodge();
		}
		return attackerDice;
	}

	/**
	 * 傷害為0
	 *
	 * @param pc
	 * @return true 傷害為0
	 */
	protected static boolean dmg0(final L1Character character) {
		try {
			if (character == null) {
				return false;
			}

			if (character.getSkillisEmpty()) {
				return false;
			}

			if (character.getSkillEffect().size() <= 0) {
				return false;
			}

			for (final Integer key : character.getSkillEffect()) {
				final Integer integer = L1AttackList.SKM0.get(key);
				if (integer != null) {
					return true;
				}
			}

		} catch (final ConcurrentModificationException e) {
			// 技能取回發生其他線程進行修改
		} catch (final Exception e) {
			// _log.error(e.getLocalizedMessage(), e);
		}
		return false;
	}

	protected L1PcInstance _pc = null;

	protected L1Character _target = null;

	protected L1PcInstance _targetPc = null;

	protected L1NpcInstance _npc = null;

	protected L1NpcInstance _targetNpc = null;

	protected int _targetId;

	protected int _targetX;

	protected int _targetY;

	protected int _statusDamage = 0;

	protected int _hitRate = 0;

	protected int _calcType;

	protected static final int PC_PC = 1;

	protected static final int PC_NPC = 2;

	protected static final int NPC_PC = 3;

	protected static final int NPC_NPC = 4;

	protected boolean _isHit = false;

	protected int _damage = 0;

	protected int _drainMana = 0;

	protected int _drainHp = 0;

	protected int _attckGrfxId = 0;

	protected int _attckActId = 0;

	// 攻撃者がプレイヤーの場合の武器情報
	protected L1ItemInstance weapon = null;

	protected int _weaponId = 0;

	/**
	 * [weapon]
sword:4, dagger:46, tohandsword:50, bow:20, blunt:11, spear:24, staff:40, throwingknife:2922, arrow:66, gauntlet:62, claw:58, edoryu:54, singlebow:20, singlespear:24, tohandblunt:11, tohandstaff:40, kiringku:58, chainsword:24 
*/
	protected int _weaponType = 0;

	protected int _weaponType2 = 0;

	protected int _weaponAddHit = 0;

	protected int _weaponAddDmg = 0;

	protected int _weaponSmall = 0;

	protected int _weaponLarge = 0;

	protected int _weaponRange = 1;

	protected int _weaponBless = 1;

	protected int _weaponEnchant = 0;

	protected int _weaponMaterial = 0;

	protected L1Item _weaponitem;
	// TODO 魔法武器卷軸by missu0524
	// protected int _weaponSkillType = 0;
	// TODO 魔法武器卷軸by missu0524

	protected int _weaponDoubleDmgChance = 0;

	protected int _weaponAttrEnchantKind = 0;

	protected int _weaponAttrEnchantLevel = 0;

	protected L1ItemInstance _arrow = null;

	protected L1ItemInstance _sting = null;
	protected int _leverage = 10; // 1/10倍で表現する。

	/**
	 * 攻擊資訊送出
	 */
	public abstract void action();

	public final void actionCounterBarrier() {
		if (this._calcType == PC_PC) {
			final int pcId = this._pc.getId();
			this._pc.setHeading(this._pc.targetDirection(this._targetX,this._targetY)); // 向きのセット
			this._pc.sendPacketsX8(new S_AttackMissPacket(this._pc,this._targetId));
			this._pc.sendPacketsX8(new S_DoActionGFX(pcId,
					ActionCodes.ACTION_Damage));
		} else if (this._calcType == NPC_PC) {
			int actId = 0;
			this._npc.setHeading(this._npc.targetDirection(this._targetX,this._targetY)); // 向きのセット
			if (this.getActId() > 0) {
				actId = this.getActId();
			} else {
				actId = ActionCodes.ACTION_Attack;
			}
			final int gfxid = this.getGfxId();
			final int npcId = this._npc.getId();
			if (gfxid > 0) {
				this._npc.broadcastPacketX8(new S_UseAttackSkill(this._target,
						npcId, gfxid, this._targetX, this._targetY, actId, 0));
			} else {
				this._npc.broadcastPacketX8(new S_AttackMissPacket(this._npc,this._targetId, actId));
			}
			this._npc.broadcastPacketX8(new S_DoActionGFX(npcId,ActionCodes.ACTION_Damage));
		}
	}

	/**
	 * 底比斯武器魔法的效果
	 */
	public abstract void addChaserAttack();

	// ●●●● 武器の属性強化による追加ダメージ算出 ●●●●
	protected int calcAttrEnchantDmg(double dmg) {
		if (dmg <= 0) {
			return 0;
		}
		if (this._calcType == PC_NPC) {

			final int weakAttr = this._targetNpc.getNpcTemplate().get_weakAttr();

			dmg *= 1 + this._pc.getAttrDmg(weakAttr);
		}
		if (this._weaponAttrEnchantKind == 0) {

			return (int) dmg;
		}

		// int weakAttr = _targetNpc.getNpcTemplate().get_weakAttr();
		// if ((weakAttr & 1) == 1 && _weaponAttrEnchantKind == 1 // 地
		// || (weakAttr & 2) == 2 && _weaponAttrEnchantKind == 2 // 火
		// || (weakAttr & 4) == 4 && _weaponAttrEnchantKind == 4 // 水
		// || (weakAttr & 8) == 8 && _weaponAttrEnchantKind == 8) { // 風
		// damage = _weaponAttrEnchantLevel;
		// }

		if (this._calcType == PC_NPC) {
			final int weakAttr = this._targetNpc.getNpcTemplate().get_weakAttr();
			/*
			 * if ((_weaponAttrEnchantKind == 1 && weakAttr == 1) // 地 ||
			 * (_weaponAttrEnchantKind == 2 && weakAttr == 2) // 火 ||
			 * (_weaponAttrEnchantKind == 4 && weakAttr == 4) // 水 ||
			 * (_weaponAttrEnchantKind == 8 && weakAttr == 8)) { // 風 resist =
			 * -50; }
			 */

			double dmgup = dmg;
			dmgup *= L1AttackList.ATTRDMGTONPC.get(this._weaponAttrEnchantLevel);

			switch (weakAttr) {

			case 0:// 無屬性怪物
				if (this._weaponAttrEnchantKind == 5|| this._weaponAttrEnchantKind == 6) {
					dmg += (int) dmgup >> 1;
				}
				break;
			case 1:// 害怕地屬性 表示怪物為風屬性 所以剋水 opqlo
				switch (this._weaponAttrEnchantKind) {
				case 1:
					dmg += dmgup;
					break;
				case 4:
					dmg -= (int) dmgup >> 1;
					break;
				case 5:
					dmg += (int) dmgup >> 1;
					break;
				case 6:
					dmg += (int) dmgup >> 1;
					break;
				}
				break;

			case 2:// 害怕火屬性 表示怪物為地屬性 所以剋風 opqlo
				switch (this._weaponAttrEnchantKind) {
				case 2:
					dmg += dmgup;
					break;
				case 8:
					dmg -= (int) dmgup >> 1;
					break;
				case 5:
					dmg += (int) dmgup >> 1;
					break;
				case 6:
					dmg += (int) dmgup >> 1;
					break;
				}
				break;

			case 4:// 害怕水屬性 表示怪物為火屬性 所以剋地 opqlo
				switch (this._weaponAttrEnchantKind) {
				case 4:
					dmg += dmgup;
					break;
				case 1:
					dmg -= (int) dmgup >> 1;
					break;
				case 5:
					dmg += (int) dmgup >> 1;
					break;
				case 6:
					dmg += (int) dmgup >> 1;
					break;
				}
				break;

			case 8:// 害怕風屬性 表示怪物為水屬性 所以剋火 opqlo
				switch (this._weaponAttrEnchantKind) {
				case 8:
					dmg += dmgup;
					break;
				case 2:
					dmg -= (int) dmgup >> 1;
					break;
				case 5:
					dmg += (int) dmgup >> 1;
					break;
				case 6:
					dmg += (int) dmgup >> 1;
					break;
				}
				break;

			case 5:// 害怕光屬性 表示怪物為闇屬性 opqlo
				if (this._weaponAttrEnchantKind == 5) {
					dmg += dmgup;
				}
				break;

			case 6:// 害怕闇屬性 表示怪物為光屬性 opqlo
				if (this._weaponAttrEnchantKind == 6) {
					dmg += dmgup;
				}
				break;
			}

			// System.out.println("懼怕:"+weakAttr+" 原傷害:"+dmg+" 加成:"+_pc.getAttrDmg(weakAttr)
			// + "總傷害:" + (dmg * _pc.getAttrDmg(weakAttr)));

			return (int) dmg;

			// XXX 耐性処理は本来、耐性合計値ではなく、各値を個別に処理して総和する。
			// int resist = 0;

		} else {

			int resist = 10;

			switch (this._weaponAttrEnchantKind) {

			case 1:// 地
				resist = this._targetPc.getEarth();
				break;

			case 2:// 火
				resist = this._targetPc.getFire();
				break;

			case 4: // 水
				resist = this._targetPc.getWater();
				break;

			case 8: // 風
				resist = this._targetPc.getWind();
				break;
			}

			int resistFloor = (int) (0.32 * Math.abs(resist));// opqlo
			// Math.abs(int)
			// 無論正負數 接傳回 正值
			// 如 -32 傳回 32
			if (resist >= 0) {
				resistFloor *= 1;
			} else {
				resistFloor *= -1;
			}

			final double attrDeffence = resistFloor / 32.0;
			final double attrCoefficient = 1 - attrDeffence;
			int damage = 0;
			damage = L1AttackList.ATTRDMGTOPC.get(this._weaponAttrEnchantLevel);
			damage *= attrCoefficient;

			return damage;
		}
	}

	// ●●●● プレイヤーのダメージ強化魔法 ●●●●
	protected double calcBuffDamage(double dmg) {
		if (dmg <= 0) {
			return 0;
		}
		// 火武器、バーサーカーのダメージは1.5倍しない
		if (this._pc.hasSkillEffect(BURNING_SPIRIT)
				|| this._pc.hasSkillEffect(ELEMENTAL_FIRE)
				&& this._weaponType != 20 && this._weaponType != 62
				&& this._weaponType2 != 17) {
			if (Random.nextInt(100) + 1 <= 33) {
				double tempDmg = dmg;

				if (this._pc.hasSkillEffect(BERSERKERS)) {
					tempDmg -= 5;
				}
				if (this._pc.hasSkillEffect(FIRE_WEAPON)) {
					tempDmg -= 4;
				} else if (this._pc.hasSkillEffect(FIRE_BLESS)) {
					tempDmg -= 4;
				} else if (this._pc.hasSkillEffect(BURNING_WEAPON)) {
					tempDmg -= 6;
				}
				final double diffDmg = dmg - tempDmg;
				dmg = tempDmg * 1.5 + diffDmg;
			}
		}

		return dmg;
	}

	/**
	 * 反擊屏障的傷害反擊計算
	 *
	 * @return
	 */
	protected int calcCounterBarrierDamage() {
		int damage = 0;
		try {
			// 反擊對象是PC
			if (this._targetPc != null) {
				final L1ItemInstance weapon = this._targetPc.getWeapon();
				if (weapon != null) {
					if (weapon.getItem().getType() == 3) { // 雙手劍
						// (BIG最大ダメージ+強化数+追加ダメージ)*2
						// (>> 1: 除) (<< 1: 乘)
						damage = weapon.getItem().getDmgLarge()
								+ weapon.getEnchantLevel()
								+ weapon.getItem().getDmgModifier();// * 2;

						/********* 幽能攻擊公式(直接傷害) *********/
						// opqlo 額外攻擊力
						final int ExtraDmg = this._targetPc.getExtraDmg();
						damage = damage + ExtraDmg;
						// opqlo 額外攻擊力

						if (this._npc != null) {
							damage = (int) this.calcBuffDamage(damage);
							damage += (int) L1WeaponSkill.getWeaponSkillDamage(this._targetPc, this._npc,weapon.getItemId());
							damage += this._pc.getClassFeature().getAttackLevel(this._pc.getLevel());// 職業傷害補正
							damage *= this.getSpAttack();// 種族相剋
							damage = this.calcAttrEnchantDmg(damage); // 属性強化ダメージボーナスopqlo
							// 屬性相剋改寫
							/********************* 攻擊力減少公式 *************************/

							damage -= this.calcPcDefense();// 被攻擊者防禦力傷害直減低
							damage -= this.calcNpcDamageReduction(); // opqlo
							// 怪物減傷公式

							final int DmgReduce = this._npc.getDmgReduceRate();
							if (DmgReduce > 0) { // opqlo 怪物減傷倍率
								damage = Math.max(damage / DmgReduce, 1);
							}

						} else if (this._pc != null) {
							damage += (int) L1WeaponSkill.getWeaponSkillDamage(
									this._targetPc, this._pc,
									weapon.getItemId());
							damage /= 4;
						}
					}
				}

				// 反擊對象是NPC
			} else if (this._targetNpc != null) {
				// (>> 1: 除) (<< 1: 乘)
				damage = this._targetNpc.getStr() + this._targetNpc.getLevel() << 1;// *
				// 2;
				// damage += (L1WeaponSkill.getWeaponSkillDamage(_pc,
				// _targetNpc, _weaponId))/3;

			}

		} catch (final Exception e) {
			// _log.error(e.getLocalizedMessage(), e);
		}
		return damage;
	}

	/**
	 * 傷害計算
	 *
	 * @return
	 */
	public abstract int calcDamage();

	/**
	 * ER迴避率
	 *
	 * @return true:命中 false:未命中
	 */
	protected boolean calcErEvasion() {

		final int rnd = Random.nextInt(100) + 1;
		return this._targetPc.getEr() < rnd;
	}

	public abstract boolean calcHit();

	protected int calcMaterialBlessDmg() {
		int damage = 0;
		final int undead = this._targetNpc.getNpcTemplate().get_undead();
		if ((this._weaponMaterial == 14 || this._weaponMaterial == 17 || this._weaponMaterial == 22)
				&& (undead == 1 || undead == 3 || undead == 5)) { // 銀・ミスリル・オリハルコン、かつ、アンデッド系・アンデッド系ボス・銀特効モンスター
			damage += Random.nextInt(20) + 1;
		}
		if ((this._weaponMaterial == 17 || this._weaponMaterial == 22)
				&& undead == 2) { // ミスリル・オリハルコン、かつ、悪魔系
			damage += Random.nextInt(3) + 1;
		}
		if (this._weaponBless == 0
				&& (undead == 1 || undead == 2 || undead == 3)) { // 祝福武器、かつ、アンデッド系・悪魔系・アンデッド系ボス
			damage += Random.nextInt(4) + 1;
		}
		if (this._pc.getWeapon() != null && this._weaponType != 20
				&& this._weaponType != 62
				&& this.weapon.getHolyDmgByMagic() != 0
				&& (undead == 1 || undead == 3)) {
			damage += this.weapon.getHolyDmgByMagic();
		}

		return damage;
	}

	/**
	 * (NPC防禦力 + 額外傷害減低) 傷害減低
	 *
	 * @return
	 */
	protected int calcNpcDamageReduction() {
		// TEST
		final int damagereduction = this._targetNpc.getNpcTemplate()
				.get_damagereduction();// 額外傷害減低
		try {
			final int srcac = this._targetNpc.getAc();
			final int ac = Math.max(0, 10 - srcac);

			final int acDefMax = ac / 7;// 防禦力傷害減免降低1/7 XXX
			if (acDefMax != 0) {
				final int srcacd = Math.max(1, acDefMax);// XXX
				return Random.nextInt(acDefMax) + srcacd + damagereduction;
			}

		} catch (final Exception e) {
			// _log.error(e.getLocalizedMessage(), e);
		}

		return damagereduction;
	}

	/**
	 * PC防禦力傷害直減低
	 *
	 * @return
	 */
	protected int calcPcDefense() {
		try {
			if (this._targetPc != null) {
				final int ac = Math.max(0, 10 - this._targetPc.getAc());

				final int acDefMax = this._targetPc.getClassFeature().getAcDefenseMax(ac);
				if (acDefMax != 0) {
					// (>> 1: 除) (<< 1: 乘) XXX
					final int srcacd = Math.max(1, acDefMax >> 3);
					final int acdown = Random.nextInt(acDefMax) + srcacd;
					// System.out.println("acdown:"+acdown+" srcacd:"+srcacd);
					return acdown;
				}
			}

		} catch (final Exception e) {
			// _log.error(e.getLocalizedMessage(), e);
		}
		return 0;
	}

	/**
	 * 武器MP吸收量計算
	 */
	public abstract void calcStaffOfMana();

	/**
	 * 計算結果反映
	 */
	public abstract void commit();

	/**
	 * 反擊屏障的傷害反擊
	 */

	public abstract void commitCounterBarrier();

	public int getActId() {
		return this._attckActId;
	}

	public int getGfxId() {
		return this._attckGrfxId;
	}

	/**
	 * 攻擊倍率(1/10)
	 *
	 * @return
	 */
	protected int getLeverage() {
		return this._leverage;
	}

	protected double getSpAttack() {
		// 0=普通、1=不死系、2=惡魔系、3=BOSS系、4=亡靈系、5=狼人系、6=龍系、7=人類
		if (this._targetNpc != null) {
			return this._pc.getEthncityDmg(this._targetNpc.getNpcTemplate().get_undead())+ this._pc.getSizeDmg(this._targetNpc.isBigSize);
		} else if (this._targetPc != null) {
			return this._pc.getEthncityDmg(7);
		}
		return 0;
	}

	protected double getWeakNess() {

		if (Random.nextInt(100) + 1 < 35) {
			if (this._pc.hasSkillEffect(SPECIAL_EFFECT_WEAKNESS_LV1)) {
				return 1.2;// TODO %3變更%20弱點曝光傷害加成
			} else if (this._pc.hasSkillEffect(SPECIAL_EFFECT_WEAKNESS_LV2)) {
				return 1.4;// TODO %6變更%40弱點曝光傷害加成
			} else if (this._pc.hasSkillEffect(SPECIAL_EFFECT_WEAKNESS_LV3)) {
				return 1.8;// TODO %9變更%20弱點曝光傷害加成
			}
		}

		return 1;

	}

	/**
	 * 攻擊使用武器是否為近距離武器判斷
	 *
	 * @return
	 */
	public abstract boolean isShortDistance();

	public void setActId(final int actId) {
		this._attckActId = actId;
	}

	public void setGfxId(final int gfxId) {
		this._attckGrfxId = gfxId;
	}

	/**
	 * 攻擊倍率(1/10)
	 *
	 * @param i
	 */
	public void setLeverage(final int i) {
		this._leverage = i;
	}

	/** 弱點曝光 */
	protected void WeaknessExposure() {
		final int random = Random.nextInt(100) + 1;

		// TODO 使用屠宰者狀態
		if (this._pc.hasSkillEffect(FOE_SLAYER)) {
			return;
		}
		if (this._pc.hasSkillEffect(SPECIAL_EFFECT_WEAKNESS_LV3)) {// TODO 目前階段三
			if (random > 40 && random <= 50) {// TODO 階段三
				this._pc.killSkillEffectTimer(SPECIAL_EFFECT_WEAKNESS_LV3);
				this._pc.setSkillEffect(SPECIAL_EFFECT_WEAKNESS_LV3, 5000);
				this._pc.sendPackets(new S_SkillIconGFX(75, 3));
			}
		} else if (this._pc.hasSkillEffect(SPECIAL_EFFECT_WEAKNESS_LV2)) {// TODO 目前階段二
			if (random <= 15) {// TODO 階段二
				this._pc.killSkillEffectTimer(SPECIAL_EFFECT_WEAKNESS_LV2);
				this._pc.setSkillEffect(SPECIAL_EFFECT_WEAKNESS_LV2, 10000);
				this._pc.sendPackets(new S_SkillIconGFX(75, 2));
			} else if (random >= 85) {// TODO 階段三
				this._pc.killSkillEffectTimer(SPECIAL_EFFECT_WEAKNESS_LV2);
				this._pc.setSkillEffect(SPECIAL_EFFECT_WEAKNESS_LV3, 5000);
				this._pc.sendPackets(new S_SkillIconGFX(75, 3));
			}
		} else if (this._pc.hasSkillEffect(SPECIAL_EFFECT_WEAKNESS_LV1)) {// TODO 目前階段一
			if (random <= 40) {// TODO 階段一
				this._pc.killSkillEffectTimer(SPECIAL_EFFECT_WEAKNESS_LV1);
				this._pc.setSkillEffect(SPECIAL_EFFECT_WEAKNESS_LV1, 16000);
				this._pc.sendPackets(new S_SkillIconGFX(75, 1));
			} else if (random >= 85) {// TODO 階段二
				this._pc.killSkillEffectTimer(SPECIAL_EFFECT_WEAKNESS_LV1);
				this._pc.setSkillEffect(SPECIAL_EFFECT_WEAKNESS_LV2, 10000);
				this._pc.sendPackets(new S_SkillIconGFX(75, 2));
			}
		} else {
			if (random <= 20) {// TODO 階段一
				this._pc.setSkillEffect(SPECIAL_EFFECT_WEAKNESS_LV1, 16000);
				this._pc.sendPackets(new S_SkillIconGFX(75, 1));
			}
		}
	}
}
